﻿/*****************************************************************
 * Copyright (C) Egosoft Co, Ltd. All rights reserved.
 * 
 * Author:   wanglj
 * Email:    wanglj2007@hotmail.com
 * Create Date:  2011/03/01
 * Usage:
 *
 * RevisionHistory：
 * Date         Author      Version         Description
 * 2011/03/01   libra       1.0             项目初建
 *
 * 
 * Remark:
 * 
 * 升级文件采用XML格式，如下：
 * <?xml version="1.0" encoding="utf-8" ?>
 * <UpgradeConfig>
 *      <file path="http://Localhost/upgradesite/file1.dll"  version="1.0.0.0" />
 *      <file path="http://Localhost/upgradesite/file2.dll"  version="1.0.0.0" />
 * </UpgradeConfig>
 * Release 1.0 on 2011.03.02 16:39
 * 升级文件只需在服务器端存放一份，客户端会自动从服务器端下载
*****************************************************************/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Windows;
using System.Windows.Threading;
using SAF.Framework.Controls.Properties;
using SAF.Framework.Controls.Upgrade;
using System.Windows.Controls;

namespace SAF.Framework.Controls
{
    /// <summary>
    /// 升级控件
    /// <para>用户需截获处理升级过程中产生的异常，可用AutoUpgrader.ShowUpgradeException()方法显示具体的异常信息；</para>
    /// <para>如用户不截获处理升级过程中产生的异常，一旦在升级过程中产生异常，应用程序将自动退出。</para>
    /// </summary>
    public class AutoUpgrader
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public AutoUpgrader()
            : this(string.Empty, string.Empty)
        {

        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="versionFileUrl">升级配置文件URL</param>
        public AutoUpgrader(string versionFileUrl)
            : this(versionFileUrl, string.Empty)
        {
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="versionFileUrl">升级配置文件URL</param>
        /// <param name="title">UpgradeWizardTitle</param>
        public AutoUpgrader(string versionFileUrl, string title)
        {
            this.m_VersionFileUrl = versionFileUrl;
            this.m_Title = title;
        }
        /// <summary>
        /// 显示应用程序升级时出现的异常
        /// </summary>
        /// <param name="ex"></param>
        public static void ShowUpgradeException(Exception ex)
        {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.AppendFormat(Resources.UpgradeException + "\n{0}", ex.Message);
            if (ex.InnerException != null)
            {
                stringBuilder.AppendFormat("\n {0}", ex.InnerException.Message);
            }
            stringBuilder.AppendFormat("\n\n" + Resources.UpgradeExceptionSource + " {0}", ex.Source);
            stringBuilder.AppendFormat("\n" + Resources.UpgradeExceptionTargetSite + " {0}", ex.TargetSite);
            MessageBox.Show(stringBuilder.ToString(), Resources.UpgradeWizardDefaultTitle, MessageBoxButton.OK, MessageBoxImage.Warning);
        }

        private string m_VersionFileUrl = string.Empty;
        /// <summary>
        /// 版本信息文件全路径
        /// </summary>
        public string VersionFileUrl
        {
            get { return m_VersionFileUrl; }
            set { m_VersionFileUrl = value; }
        }
        private string m_Title = string.Empty;
        /// <summary>
        /// 升级向导窗口的标题
        /// </summary>
        public string Title
        {
            get
            {
                return string.IsNullOrEmpty(m_Title) ? Resources.UpgradeWizardDefaultTitle : m_Title.Trim() + " - " + Resources.UpgradeWizardDefaultTitle;
            }
            set { m_Title = value; }
        }
        /// <summary>
        /// 升级核心功能函数
        /// </summary>
        public void Upgrade()
        {
            try
            {
                List<DownloadFile> downloadFilesList = GetDownloadFiles();
                //有文件更新时，下载服务器上的配置文件
                if (downloadFilesList.Count > 0)
                {
                    UpgradeConfigFile configFile = new UpgradeConfigFile();
                    configFile.path = this.m_VersionFileUrl;
                    configFile.version = "1.0.0.0";
                    downloadFilesList.Add(new DownloadFile(configFile));

                    Helper.ApplicationShutDownMode = Application.Current.ShutdownMode;
                    Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;

                    //有文件需升级才弹出升级界面
                    UpgradeWizard wizard = new UpgradeWizard();
                    wizard.DownloadFileList = downloadFilesList;
                    wizard.Title = this.Title;
                    wizard.ShowDialog();

                    if (Application.Current != null)
                    {
                        Application.Current.ShutdownMode = Helper.ApplicationShutDownMode;
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 检查是否需要升级
        /// </summary>
        /// <returns></returns>
        public bool CheckUpgrade()
        {
            try
            {
                List<DownloadFile> downloadFilesList = GetDownloadFiles();
                if (downloadFilesList.Count > 0)
                    return true;
                else
                    return false;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 获取需要升级的文件列表
        /// </summary>
        /// <returns></returns>
        private List<DownloadFile> GetDownloadFiles()
        {
            List<DownloadFile> downloadFilesList = new List<DownloadFile>();
            UpgradeConfig remoteConfig = GetRemoteConfig();
            UpgradeConfig localConfig = GetLocalConfig();
            if (localConfig == null)
            {
                //如果本地配置文件不存，则将远程文件全加入到下载列表中
                foreach (var item in remoteConfig.file)
                {
                    if (!downloadFilesList.Exists(file => file.Path == item.path))
                        downloadFilesList.Add(new DownloadFile(item));
                }
            }
            else
            {
                Dictionary<string, UpgradeConfigFile> localFiles = new Dictionary<string, UpgradeConfigFile>();
                //将本地配置信息放到字典里
                foreach (UpgradeConfigFile file in localConfig.file)
                {
                    if (!localFiles.ContainsKey(file.path))
                        localFiles.Add(file.path, file);
                }
                //检查远程的配置文件
                foreach (UpgradeConfigFile remoteFile in remoteConfig.file)
                {
                    //如果远程配置在本地存在，则判断二者的版本号；否则将远程文件直接添加到下载无表
                    if (localFiles.ContainsKey(remoteFile.path))
                    {
                        //先找出本地的文件配置
                        UpgradeConfigFile localFile = localFiles[remoteFile.path];
                        //比较本地与远程的版本
                        Version verRemote = new Version(remoteFile.version);
                        Version verLocal = new Version(localFile.version);
                        if (verRemote != verLocal)
                        {
                            if (!downloadFilesList.Exists(file => file.Path == remoteFile.path))
                                downloadFilesList.Add(new DownloadFile(remoteFile));
                        }
                    }
                    else
                    {
                        if (!downloadFilesList.Exists(file => file.Path == remoteFile.path))
                            downloadFilesList.Add(new DownloadFile(remoteFile));
                    }
                }
            }
            return downloadFilesList;
        }
        /// <summary>
        /// 获取本地配置
        /// </summary>
        /// <returns></returns>
        private UpgradeConfig GetLocalConfig()
        {
            string localFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
                Path.GetFileName(this.m_VersionFileUrl));
            try
            {
                if (File.Exists(localFileName))
                {
                    return Helper.XmlFile2Entity<UpgradeConfig>(localFileName);
                }
                else
                {
                    return null;
                }
            }
            catch
            {
                //本地文件出错，则返回NULL,由升级程序重新下载所有文件
                return null;
            }
        }
        /// <summary>
        /// 获取远程的配置文件
        /// </summary>
        /// <returns></returns>
        private UpgradeConfig GetRemoteConfig()
        {
            if (string.IsNullOrWhiteSpace(this.m_VersionFileUrl))
                throw new Exception(Resources.VersionFileUrlIsNull);

            try
            {
                WebClient client = new WebClient();
                string xmlString = client.DownloadString(this.m_VersionFileUrl);
                UpgradeConfig remoteConfig = Helper.XmlString2Entity<UpgradeConfig>(xmlString);
                return remoteConfig;
            }
            catch (Exception ex)
            {
                throw new Exception(Resources.RemoteConfigFileError, ex);
            }
        }
    }
}
